var util = require('./util');
var EventEmitter = process.EventEmitter;
var events = require('events');
var emitter = new EventEmitter();
var crypto = require('crypto');
var http = require('http');

/**
 * 创建构造函数
 * @constructor
 * @param {Object} [options]
 */
function push (options) {
	this.options = {
		APPID: null,
		APPKEY: null,
		MASTERSECRET: null,
		appidlists: [],
		PUSH_ERROR_EVENT: 'push-error',
		PUSH_SUCCESS_EVENT: 'push-success',
		MsgTypes: ['TransmissionMsg', 'NotifyMsg', 'LinkMsg'],
		PushIcon: 'push.png'
	};
	//此参数的配置要和pushMessage接口里的params中的参数保持一致
	this.pushMessageKeys = ['action', 'appkey', 'appid', 'data', 'clientid', 'expire'];
	//此参数的配置要和pushSpecifyMessage接口里的params中的参数保持一致
	this.specifyMessageKeys = ['action', 'appkey', 'type', 'pushTitle', 'pushType', 'offline', 'offlineTime', 'priority', 'msg', 'tokenMD5List'];
	//此参数的配置要和pushGroupMessage接口里的params中的参数保持一致
	this.gtoupMessageKeys = ['action', 'appkey', 'type', 'pushTitle', 'pushType', 'offline', 'offlineTime', 'priority', 'isDirected', 'msg', 'appIdList'];
	this.content = undefined;
	this.clientid = undefined;
	this.clientids = [];
	this.title = undefined;
	this.appidlists = [this.options.APPID];
	this.envchan = emitter;
	this.request = {
		hostname: 'sdk.open.api.igexin.com',
		port: 80,
		path: '/service',
		method: 'POST'
	};
	util.extend(this.options, options);
}


//获取正确的Content-Length的长度，在JS中一个汉字只按一个字节算，实际要按三个字节
push.prototype.getStringBytesCount = function(c) {
	var n = c.length,s;
	var len = 0;
	for(var i=0; i <n;i++){
		s=c.charCodeAt(i);

		if( s < 0x0080 )
			len++;
		else if( s < 0x0800 )
			len += 2;
		else
			len += 3;
	}
	return len;
}   


push.prototype.post = function(data, envchan) {
	var headers = {
		'Content-Type': 'text/html;charset=utf8',
		'Content-Length': this.getStringBytesCount(data) //获取正确的Content-Length的长度
	};

	this.request.headers = headers;
	//console.log('headers=====' + headers);

	var req = http.request(this.request, function(res) {
	//	console.log('STATUS: ' + res.statusCode);
	//	console.log('HEADERS: ' + JSON.stringify(res.headers));
		res.setEncoding('utf8');
		res.on('data', function (chunk) {
			//console.log('BODY: ' + chunk);
			envchan.emit('push-success', chunk);
		});
	});

	req.on('error', function(e) {
		//console.log('problem with request: ' + e.message);
		envchan.emit('push-error', e.message);
	});

	// write data to request body
	req.write(data);
	req.end();
}

/**
 * 生成 link 消息，对应消息类型LinkMsg
 */
push.prototype.genlinkMsg = function() {
	return {
		linkMsgIcon: this.options.PushIcon,		//消息在通知栏的图标
		linkMsgTitle: this.title,		//推送消息的标题
		linkMsgContent: this.content,	//推送消息的内容
		linkMsgUrl: this.options.linkurl,		//点击通知跳转的目标网页
	};
}


/**
 * 生成 通知 消息，对应消息类型NotifyMsg
 */
push.prototype.genNotifyMsg = function(){
    return {
        notifyMsgIcon: this.PushIcon,		//消息在通知栏的图标
        notifyMsgTitle: this.title,			//推送消息的标题
        notifyMsgContent: this.content,		//推送消息的内容
        transmissionContent: this.content,	//透传消息内容
        transmissionType: 1				//收到消息是否立即启动应用，1 为立即启动，2 则广播等待客户端自启动
    };
}

/**
 * 生成 透传 消息，对应消息类型TransmissionMsg
 */
push.prototype.genTransmissionMsg = function () {
	return {
		transmissionContent: this.content, //透传消息内容
		transmissionType: 2 //收到消息是否立即启动应用，1, 立即启动，2, 则广播等待客户端自启动
	};
}


/**
 * 根据消息类型生成消息体
 * @param msgType 消息类型
 * @return {*}
 */
push.prototype.getMsg = function (msgType){
    var msg;
    switch(msgType){
        case 0:
            msg = this.genTransmissionMsg();
            break;
        case 1:
            msg = this.genNotifyMsg();
            break;
        case 2:
            msg = this.genlinkMsg();
            break;
        default:
            break;
    }
	
    return msg;
}


/*
 *向指定的一个用户推送消息
 */
push.prototype.pushMessage = function(msgType){
	var params = {
	        action: "pushmessage",
		appkey: this.options.APPKEY,
		appid: this.options.APPID,
		data: this.content,		//您需要透传的内容
            	clientid: this.clientid, //您获取的ClientID
            	expire: 3600		//消息超时时间，单位为秒，可选,
	};
	
	//获取sign值
	params.sign = this.makeSign(params, this.pushMessageKeys);
	//post发送消息
	this.post(JSON.stringify(params), this.envchan);
};

/*
 *向指定的多个用户推送消息
 */
push.prototype.pushSpecifyMessage = function(msgType){
	var params = {
	        action: "pushSpecifyMessage",
		appkey: this.options.APPKEY,
		type: 2,						//推送类型：2为消息
		pushTitle: "许愿树",				//pushTitle请填写您的应用名称
		pushType: this.options.MsgTypes[msgType],	//推送消息类型，有TransmissionMsg、LinkMsg、NotifyMsg三种，此处以NotifyMsg举例
		offline: true,					//是否进入离线消息
		offlineTime: 24,				//消息保留时间
		priority: 1,					//推送任务优先级
		msg: this.getMsg(msgType),			//notifyMsg消息实体
		tokenMD5List: this.clientids			//给指定clientid 推送消息，最多500个clientid，单个clientid不超过32byte
	};
		
	//获取sign值
	params.sign =  this.makeSign(params, this.specifyMessageKeys); 
	//console.log('params.sign=====' + params.sign);
	//post发送消息
	this.post(JSON.stringify(params), this.envchan);
};


/*
 *向应用的所有用户推送消息
 */
push.prototype.pushGroupMessage = function(msgType){
	var params = {
	        action: "pushGroupMessage",
		appkey: this.options.APPKEY,
		type: 2,					//推送类型：2为消息
		pushTitle: '许愿树',			//pushTitle请填写您的应用名称
		pushType: this.options.MsgTypes[msgType],	//推送消息类型，有TransmissionMsg、LinkMsg、NotifyMsg三种，此处以LinkMsg举例
		offline: true,					//是否进入离线消息
		offlineTime: 24,				//消息保留时间
		priority: 1,					//推送任务优先级
		isDirected: false,				//推是否定向推送
		msg: this.getMsg(msgType),			//linkMsg消息实体
		appIdList: this.appidlists			//客户端应用标识列表，对应您应用的AppID
	};
	
	//获取sign值
	params.sign = this.makeSign(params, this.gtoupMessageKeys);
	//post发送消息
	this.post(JSON.stringify(params), this.envchan);
};

/*---
计算sign值:
sign=md5(mastersecret +”action”+ pushGroupMessage +…….)
排序规则第一个为mastersecret值（该值不在参数序列中），之后是根据参数的
key值英文字母序排列（本次包中没有包含该key的则不需要列入），
最后获得masterSecret+key值+value值取和之后求其md5值
（参与求和的类型有：String，Long，Integer共三种类型; ）
---*/
push.prototype.makeSign = function(pramasObj, keys){
    var sign = this.options.MASTERSECRET;
	keys.sort();
	for(var i = 0, len = keys.length; i < len; i++){
        	var key = keys[i], value = pramasObj[keys[i]];
		if(value.constructor==String || this.isInteger(value)){
		    console.log(keys[i] + ':' + pramasObj[keys[i]]);
		    sign += keys[i] + pramasObj[keys[i]];
		}
	}
	//获取sign的md5加密值
	return this.md5(sign);
}

/**
 * 是否是整型
 */
push.prototype.isInteger = function (obj){
    var num = new RegExp(/^[-\+]?\d+$/);
    if (isNaN(obj)) {
        return false
    }
    else{
        return num.test(obj);
    }
}

/*获取sign的md5加密值
 * 此处会因中文编码不一致，导致md5加密算出来的结果会有问题，
 * 所以在此用buff模块进行了处理一下，加密结果是正确的
*/
push.prototype.md5 = function (str){
	var Buffer = require('buffer').Buffer;
	var buf = new Buffer(1024*5);
	var len = buf.write(str, 0);
	var result = buf.toString('binary', 0, len); //这里要用binary才可以使结果与sign一致,还可以用uft8,ascii 
    	var md5_value = crypto.createHash('md5').update(result).digest('hex');
	//console.log("md5_value=====" + md5_value);
	return md5_value;
}

/**
 * 监听错误
 */
push.prototype.onError = function() {
	emitter.on(this.options.PUSH_ERROR_EVENT, function (result) {
		console.log(result);	
	});
}
/**
 * 监听成功消息
 */

push.prototype.onSuccess = function() {
	emitter.on(this.options.PUSH_SUCCESS_EVENT, function (result){
		console.log(result);	
	});
}

module.exports = push;







